#pragma once

#include <string>
#include <memory>
#include <atomic>

#include "../utility/Noncopyable.h"
#include "../net/InetAddress.h"
#include "./Callbacks.h"
#include "../utility/Buffer.h"
// #include "./utility/Timestamp.h"

class EventLoop;
class Socket;
class Channel;

// 可以生成std::shared_ptr<TcpConnection>，给channel的weak_ptr<>持有延长生命周期而不会意外析构
// channel的回调是tcpconnection注册的，需要保证tcpconnection存在，才可以调用回调
class TcpConnection : Noncopyable, public std::enable_shared_from_this<TcpConnection>
{
public:
    TcpConnection(EventLoop *loop,
                  const std::string &nameArg,
                  int sockfd,
                  const InetAddress &localAddr,
                  const InetAddress &peerAddr);
    ~TcpConnection();

    // 工具方法
    EventLoop *getLoop() const;
    const std::string &getName() const;
    const InetAddress &getLocalAddr() const;
    const InetAddress &getPeerAddr() const;
    bool isConnected() const;

    void setConnectionCallback(const ConnectionCallback &cb);
    void setReadWriteCallback(const ReadWriteCallback &cb);
    void setWriteCompleteCallback(const WriteCompleteCallback &cb);
    void setCloseCallback(const CloseCallback &cb);
    void setHighWaterMarkCallback(const HighWaterMarkCallback &cb, size_t highWaterMark);

    // 外部可调用
    void connectEstablished();
    void connectDestroyed();
    void connectShutdown(); // 连接半关闭

    // 发送数据
    void sendData(const std::string &buf);
    void sendDataZeroCopy(int fd, off_t offset, size_t count); // OPTIMIZE: 新增零拷贝发送数据

private:
    // OPTIMIZE: enum -> enum class
    // 用static_cast<int> 赋值给 atomic_int
    enum class ConnState
    {
        kDisconnected, // 已经断开连接
        kConnecting,   // 正在连接
        kConnected,    // 已连接
        kDisconnecting // 正在断开连接，写关闭/断开半连接时
    };
    // 形参虽然是类但实际是小对象不用const &
    void setState(ConnState state);

    void connectShutdownInLoop();

    void handleRead(Timestamp recvTime);
    void handleWrite();
    void handleClose();
    void handleError();

    void sendDataInLoop(const void *data, size_t needWriteSize);
    void sendDataZeroCopyInLoop(int fileDescriptor, off_t offset, size_t needWriteSize);

    EventLoop *loop_;        // 所属loop
    const std::string name_; // 日志输出名称

    // 类似Acceptor
    std::unique_ptr<Socket> socket_;
    std::unique_ptr<Channel> channel_; // conn Channel

    // 连接的元信息，不一定用到
    const InetAddress localAddr_;
    const InetAddress peerAddr_;

    // 连接的状态信息
    std::atomic_int state_; // TODO：使用相关原子操作/方法处理连接状态
    bool isRead_;           // 是否在监听读事件，未用到

    // 用户->TcpServer->TcpConnection->Channel注册的回调
    ConnectionCallback connectionCallback_;       // 新连接回调，实际是创建连接/关闭连接回调
    ReadWriteCallback readWriteCallback_;         // 读写回调
    WriteCompleteCallback writeCompleteCallback_; // 写完成回调
    CloseCallback closeCallback_;                 // 关闭连接回调，实际是TcpServer::removeConnection()
    HighWaterMarkCallback highWaterMarkCallback_; // 高水位回调，要写入outputBuffer空闲可写区的数据到达阈值
    // OPTIMIZE: 构造方法初始化列表 -> 默认初始化
    size_t highWaterMark_ = 64 * 1024 * 1024; // 高水位阈值64MB，可以控制在水位线以下，比如超过阈值就暂停发送

    // 数据缓冲区
    Buffer inputBuffer_;  // 内核->Buffer->库本身/服务端
    Buffer outputBuffer_; // 库本身/服务端->buffer->内核
};